package cn.numeron.common.utility

import android.util.Log
import cn.numeron.okhttp.TextLogInterceptor
import java.io.PrintWriter
import java.io.StringWriter

object Logger : TextLogInterceptor.Logger, coil.util.Logger {

    /** HTTP相关的日志，一行最多多少个字符 */
    private const val MAX_LENGTH_LOG_LINE = 2000

    /** 日志等级，控制日志工具仅输出等级比此值大的日志 */
    override var level: Int = Log.VERBOSE
        set(value) {
            if (value !in Log.VERBOSE..Log.ASSERT) {
                throw IllegalArgumentException("Level must in ${Log.VERBOSE..Log.ASSERT}")
            }
            field = value
        }

    /** Coil的日志输出方法 */
    override fun log(tag: String, priority: Int, message: String?, throwable: Throwable?) {
        if (message != null && priority >= level) {
            Log.println(priority, tag, message)
        }
        if (throwable != null && priority >= level) {
            val writer = StringWriter()
            throwable.printStackTrace(PrintWriter(writer))
            Log.println(priority, tag, writer.toString())
        }
    }

    /** OkHttpClient的日志输出方法 */
    @Synchronized
    override tailrec fun log(message: String) {
        var lineEnd = message.indexOf('\n')
        if (lineEnd == -1) {
            lineEnd = minOf(message.length, MAX_LENGTH_LOG_LINE)
        } else if (lineEnd > MAX_LENGTH_LOG_LINE) {
            lineEnd = MAX_LENGTH_LOG_LINE
        }
        val logMessage = message.substring(0, lineEnd)
        info("OkHttp", logMessage)
        if (lineEnd < message.lastIndex) {
            if (message[lineEnd] == '\n') {
                lineEnd++
            }
            log(message.substring(lineEnd))
        }
    }

    fun verbose(tag: String, message: Any, throwable: Throwable? = null) {
        if (level <= Log.VERBOSE) {
            Log.v(tag, message.toString(), throwable)
        }
    }

    fun debug(tag: String, message: Any, throwable: Throwable? = null) {
        if (level <= Log.DEBUG) {
            Log.d(tag, message.toString(), throwable)
        }
    }

    fun info(tag: String, message: Any, throwable: Throwable? = null) {
        if (level <= Log.INFO) {
            Log.i(tag, message.toString(), throwable)
        }
    }

    fun warn(tag: String, message: Any, throwable: Throwable? = null) {
        if (level <= Log.WARN) {
            Log.w(tag, message.toString(), throwable)
        }
    }

    fun error(tag: String, message: Any, throwable: Throwable? = null) {
        if (level <= Log.ERROR) {
            Log.e(tag, message.toString(), throwable)
        }
    }

}